﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace KPM.Common.DragHelpers
{
    public partial class MouseInteraction
    {
        private static readonly DependencyProperty DoubleClickProperty = DependencyProperty.RegisterAttached("DoubleClick", typeof(ICommand), typeof(MouseInteraction), new PropertyMetadata(new PropertyChangedCallback(DoubleClickPropertyChanged)));

        private static readonly DependencyProperty LastClickTimestampProperty = DependencyProperty.RegisterAttached("LastClickTimestamp", typeof(DateTime), typeof(MouseInteraction), new PropertyMetadata(DateTime.MinValue));

        private static readonly TimeSpan Threshold = TimeSpan.FromMilliseconds(200);

        public static void SetDoubleClick(UIElement element, ICommand value)
        {
            element.SetValue(DoubleClickProperty, value);
        }

        public static ICommand GetDoubleClick(UIElement element)
        {
            return (ICommand)element.GetValue(DoubleClickProperty);
        }

        internal static DateTime GetLastClickTimestamp(UIElement element)
        {
            return (DateTime)element.GetValue(LastClickTimestampProperty);
        }

        internal static void SetLastClickTimestamp(UIElement element, DateTime value)
        {
            element.SetValue(LastClickTimestampProperty, value);
        }

        private static void DoubleClickPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            UIElement element = (UIElement)d;
            element.MouseLeftButtonUp -= DoubleClickMouseLeftButtonUp;
            if (e.NewValue != null)
            {
                element.MouseLeftButtonUp += DoubleClickMouseLeftButtonUp;
            }
        }

        private static void DoubleClickMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            UIElement element = (UIElement)sender;
            DateTime timestamp = GetLastClickTimestamp(element);
            DateTime now = DateTime.Now;
            if (timestamp == DateTime.MinValue || now - timestamp > Threshold)
            {
                SetLastClickTimestamp(element, now);
                return;
            }

            SetLastClickTimestamp(element, DateTime.MinValue);
            ICommand command = GetDoubleClick(element);
            if (command != null)
            {
                command.Execute(null);
            }
        }
    }

    public partial class MouseInteraction
    {
        private static readonly DependencyProperty CanvasDragProperty = DependencyProperty.RegisterAttached("CanvasDrag", typeof(DragDefinition), typeof(MouseInteraction), new PropertyMetadata(new PropertyChangedCallback(CanvasDragPropertyChanged)));

        public static void SetCanvasDrag(UIElement element, DragDefinition value)
        {
            element.SetValue(CanvasDragProperty, value);
        }

        public static DragDefinition GetCanvasDrag(UIElement element)
        {
            return (DragDefinition)element.GetValue(CanvasDragProperty);
        }

        private static void CanvasDragPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            UIElement element = (UIElement)d;
            DragDefinition newValue = (DragDefinition)e.NewValue;
            if (newValue != null && newValue.DragType != CanvasDragType.Unknown)
            {
                element.AddHandler(UIElement.MouseLeftButtonDownEvent, new MouseButtonEventHandler(CanvasDragMouseLeftButtonDown), true);
            }
        }

        private static void CanvasDragMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (e.Handled)
            {
                return;
            }

            if (MouseCapture.IsCaptured())
            {
                return;
            }

            UIElement element = (UIElement)sender;
            DragDefinition definition = GetCanvasDrag(element);
            if (!definition.CanDrag())
            {
                return;
            }

            element.MouseLeftButtonUp += CanvasDragMouseLeftButtonUp;
            element.MouseMove += CanvasDragMouseMove;
            //definition.DragStarted(element, e.GetPosition(element.FindVisualParent<Canvas>()));
            definition.DragStarted(element, e.GetPosition(element));
            e.Handled = true;
            MouseCapture.Capture(element);
        }

        private static void CanvasDragMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            UIElement element = (UIElement)sender;
            element.MouseLeftButtonUp -= CanvasDragMouseLeftButtonUp;
            element.MouseMove -= CanvasDragMouseMove;
            MouseCapture.Release(element);
        }

        private static void CanvasDragMouseMove(object sender, MouseEventArgs e)
        {
            UIElement element = (UIElement)sender;
            DragDefinition definition = GetCanvasDrag(element);
            definition.OnDragMove(element, e.GetPosition(element));
            //definition.OnDragMove(element, e.GetPosition(element.FindVisualParent<Canvas>()));
        }
    }
}